﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ChongJu.ModelManager.Calibration
{
    public class CalibrationModel
    {
        /// <summary>
        /// 第几次调试 第一次调试按系数增减
        /// </summary>
        public int Index { get; set; }

        /// <summary>
        /// 允许的差值
        /// </summary>
        public double AllowRange { get; set; }

        public double StandR { get; set; }

        public double StandG { get; set; }

        public double StandB { get; set; }

        public double StandLight 
        {
            get
            {
                if (this.Type == CalibrationEnum.Light)
                    return Math.Round((StandR + StandG + StandB) / 3, 2);
                else 
                    return 0;
            }
        }

        public int InitCameraR { get; set; }

        public int InitCameraG { get; set; }

        public int InitCameraB { get; set; }

        public double TestAverageR
        {
            get
            {
                if (LstImage.Count == 0)
                    return 0;

                int count = (int)(RemoveRate * 0.01 * LstImage.Count);
                if (2 * count > LstImage.Count)
                    return LstImage.Average(q => q.R);

                var temp = LstImage.OrderBy(q => q.R).ToList();
                temp.RemoveRange(0, count);
                temp.RemoveRange(temp.Count - count, count);
                return Math.Round(temp.Average(q => q.R), 2);
            }
        }

        public double TestAverageG
        {
            get
            {
                if (LstImage.Count == 0)
                    return 0;

                int count = (int)(RemoveRate * 0.01 * LstImage.Count);
                if (2 * count > LstImage.Count)
                    return LstImage.Average(q => q.G);

                var temp = LstImage.OrderBy(q => q.R).ToList();
                temp.RemoveRange(0, count);
                temp.RemoveRange(temp.Count - count, count);
                return Math.Round(temp.Average(q => q.G), 2);
            }
        }

        public double TestAverageB
        {
            get
            {
                if (LstImage.Count == 0)
                    return 0;

                int count = (int)(RemoveRate * 0.01 * LstImage.Count);
                if (2 * count > LstImage.Count)
                    return LstImage.Average(q => q.B);

                var temp = LstImage.OrderBy(q => q.R).ToList();
                temp.RemoveRange(0, count);
                temp.RemoveRange(temp.Count - count, count);
                return Math.Round(temp.Average(q => q.B), 2);
            }
        }

        public double TestAverageLight
        {
            get
            {
                if (Type == CalibrationEnum.Light)
                    return Math.Round((TestAverageR + TestAverageG + TestAverageB) / 3, 2);
                else
                    return 0;
            }
        }

        public double SubtractR
        {
            get
            {
                if (TestAverageR == 0)
                    return 0;
                else
                    return Math.Round(TestAverageR - StandR, 2);
            }
        }

        public double SubtractG
        {
            get
            {
                if (TestAverageG == 0)
                    return 0;
                else
                    return Math.Round(TestAverageG - StandG, 2);
            }
        }

        public double SubtractB
        {
            get
            {
                if (TestAverageB == 0)
                    return 0;
                else
                    return Math.Round(TestAverageB - StandB, 2);
            }
        }

        public double SubtractLight
        {
            get
            {
                if (TestAverageLight - StandLight > 10)
                    return -5;
                else if (TestAverageLight - StandLight > 5)
                    return -3;
                else if (TestAverageLight - StandLight > 0)
                    return -1;
                else if (TestAverageLight - StandLight == 0)
                    return 0;
                else if (TestAverageLight - StandLight < 5)
                    return 1;
                else if (TestAverageLight - StandLight < 10)
                    return 3;
                else
                    return 5;
            }
        }

        public double RateR
        {
            get
            {
                if (IsRate() == true)
                    return rateR;
                else
                    return 0;
            }
            set { rateR = value; }
        }
        private double rateR;

        public double RateG
        {
            get
            {
                if (IsRate() == true)
                    return rateG;
                else
                    return 0;
            }
            set { rateG = value; }
        }
        private double rateG;


        public double RateB
        {
            get
            {
                if (IsRate() == true)
                    return rateB;
                else
                    return 0;
            }
            set { rateB = value; }
        }
        private double rateB;


        public int MultiplyR
        {
            get
            {
                if (IsRate() == true)
                    return (int)(SubtractR * RateR);
                else
                    return ParserR(SubtractR);
            }
        }

        public int MultiplyG
        {
            get
            {
                if (IsRate() == true)
                    return (int)(SubtractG * RateG);
                else
                    return ParserG(SubtractG);
            }
        }

        public int MultiplyB
        {
            get
            {
                if (IsRate() == true)
                    return (int)(SubtractB * RateB);
                else
                    return ParserB(SubtractB);
            }
        }

        public int CameraR { get; set; }

        public int CameraG { get; set; }

        public int CameraB { get; set; }

        public int ResultR
        {
            get
            {
                if (TestAverageR == 0)
                    return 0;
                else
                {
                    var result = CameraR - MultiplyR;
                    if (result < InitCameraR - RangeR)
                        return InitCameraR - RangeR;
                    else if (result > InitCameraR + RangeR)
                        return InitCameraR + RangeR;
                    else
                        return result;
                }
            }
        }

        public int RangeR { get; set; }

        public int ResultG
        {
            get
            {
                if (TestAverageG == 0)
                    return 0;
                else
                {
                    var result = CameraG - MultiplyG;
                    if (result < InitCameraG - RangeG)
                        return InitCameraG - RangeG;
                    else if (result > InitCameraG + RangeG)
                        return InitCameraG + RangeG;
                    else
                        return result;
                }
            }
        }

        public int RangeG { get; set; }

        public int ResultB
        {
            get
            {
                if (TestAverageB == 0)
                    return 0;
                else
                {
                    var result = CameraB - MultiplyB;
                    if (result < InitCameraB - RangeB)
                        return InitCameraB - RangeB;
                    else if (result > InitCameraB + RangeB)
                        return InitCameraB + RangeB;
                    else
                        return result;
                }
            }
        }

        public int RangeB { get; set; }

        public int ResultLight
        {
            get
            {
                if (SubtractLight == 0)
                    return 0;
                else
                {
                    var result = CameraB - MultiplyB;
                    if (result < InitCameraB - RangeB)
                        return InitCameraB - RangeB;
                    else if (result > InitCameraB + RangeB)
                        return InitCameraB + RangeB;
                    else
                        return result;
                }
            }
        }

        public string ImageDir { get; set; }

        public int X { get; set; }

        public int Y { get; set; }

        public int W { get; set; }

        public int H { get; set; }

        public double Exposure { get; set; }

        public double Gain { get; set; }

        public List<ImageRGBModel> LstImage { get; private set; } = new List<ImageRGBModel>();

        /// <summary>
        /// 是否完成调试
        /// </summary>
        /// <returns></returns>
        public bool IsComplete
        {
            get
            {
                if (Math.Abs(SubtractR) <= AllowRange &&
                    Math.Abs(SubtractG) <= AllowRange &&
                    Math.Abs(SubtractB) <= AllowRange)
                {
                    if ((SubtractR <= 0 && SubtractG <= 0) ||
                        (SubtractR >= 0 && SubtractG >= 0))
                        return true;

                    return false;
                }
                return false;
            }
        }

        public List<CaliNewViewModel> ToView()
        {
            List<CaliNewViewModel> lst = new List<CaliNewViewModel>();

            //R
            var view = new CaliNewViewModel();
            view.Title = "R";
            view.Stand = this.StandR;
            view.Test = this.TestAverageR;
            view.Subtract = this.SubtractR;
            view.Rate = this.RateR;
            view.Multiply = this.MultiplyR;
            view.Camera = this.CameraR;
            view.Result = this.ResultR;
            view.Exposure = this.Exposure;
            view.Gain = this.Gain;
            view.Type = this.Type;
            lst.Add(view);

            //G
            view = new CaliNewViewModel();
            view.Title = "G";
            view.Stand = this.StandG;
            view.Test = this.TestAverageG;
            view.Subtract = this.SubtractG;
            view.Rate = this.RateG;
            view.Multiply = this.MultiplyG;
            view.Camera = this.CameraG;
            view.Result = this.ResultG;
            view.Exposure = this.Exposure;
            view.Gain = this.Gain;
            view.Type = this.Type;
            lst.Add(view);

            //B
            view = new CaliNewViewModel();
            view.Title = "B";
            view.Stand = this.StandB;
            view.Test = this.TestAverageB;
            view.Subtract = this.SubtractB;
            view.Rate = this.RateB;
            view.Multiply = this.MultiplyB;
            view.Camera = this.CameraB;
            view.Result = this.ResultB;
            view.Exposure = this.Exposure;
            view.Gain = this.Gain;
            view.Type = this.Type;
            lst.Add(view);

            return lst;
        }

        public CalibrationModel Clone()
        {
            return this.MemberwiseClone() as CalibrationModel;
        }

        /// <summary>
        /// 微调R
        /// </summary>
        /// <param name="r"></param>
        /// <param name="sub"></param>
        /// <returns></returns>
        private int ParserR(double sub)
        {
            var temp = Math.Abs(sub);
            var result = 0;
            if (temp <= 0.1)
                result = 0;
            else if (0.1 < temp & temp <= 0.3)
                result = 1;
            else if (0.3 < temp & temp <= 0.5)
                result = 2;
            else if (0.5 < temp & temp <= 0.8)
                result = 5;
            else if (0.8 < temp & temp <= 1)
                result = 10;
            else if (1 < temp & temp <= 2)
                result = 20;
            else
                result = 30;

            return sub > 0 ? result : 0 - result;
        }

        /// <summary>
        /// 微调G
        /// </summary>
        /// <param name="g"></param>
        /// <param name="sub"></param>
        /// <returns></returns>
        private int ParserG(double sub)
        {
            var temp = Math.Abs(sub);
            var result = 0;
            if (temp <= 0.1)
            {
                if ((Math.Abs(SubtractR) <= AllowRange && SubtractR > 0 && sub < 0) ||
                    (Math.Abs(SubtractR) <= AllowRange && SubtractR < 0 && sub > 0))
                    result = 1;
                else
                    result = 0;
            }
            else if (0.1 < temp & temp <= 0.3)
                result = 1;
            else if (0.3 < temp & temp <= 0.8)
                result = 2;
            else if (0.8 < temp & temp <= 1)
                result = 3;
            else if (1 < temp & temp <= 4)
                result = 4;
            else
                result = 6;

            return sub > 0 ? result : (0 - result);
        }

        /// <summary>
        /// 微调B
        /// </summary>
        /// <param name="b"></param>
        /// <param name="sub"></param>
        /// <returns></returns>
        private int ParserB(double sub)
        {
            var temp = Math.Abs(sub);
            var result = 0;
            if (temp <= 0.1)
                result = 0;
            else if (0.1 < temp & temp <= 0.3)
                result = 1;
            else if (0.3 < temp & temp <= 0.5)
                result = 2;
            else if (0.5 < temp & temp <= 0.8)
                result = 5;
            else if (0.8 < temp & temp <= 1)
                result = 10;
            else if (1 < temp & temp <= 2)
                result = 20;
            else
                result = 30;

            return sub > 0 ? result : (0 - result);
        }

        /// <summary>
        /// 是否按系数调试
        /// </summary>
        /// <returns></returns>
        private bool IsRate()
        {
            //1、第一次必须按系数调试
            //2、当RGB中有两个的差值 > 1 按系数调试，否则，微调

            List<double> lst = new List<double>() {
                    Math.Abs(SubtractR),
                    Math.Abs(SubtractG),
                    Math.Abs(SubtractB)
                };
            if (lst.Count(q => q > 1) >= 2)
                return true;
            else
                return false;
        }

        /// <summary>
        /// 去除最大最小RGB百分比
        /// </summary>
        public int RemoveRate { get; set; }

        public CalibrationEnum Type { get; set; }
    }

    public class CaliNewViewModel
    {
        public string Title { get; set; }

        public double Stand { get; set; }

        public double Test { get; set; }

        public double Subtract { get; set; }

        public double Rate { get; set; }

        public int Multiply { get; set; }

        public int Camera { get; set; }

        public int Result { get; set; }

        public double Exposure { get; set; }

        public double Gain { get; set; }

        public CalibrationEnum Type { get; set; }
    }

    public class ImageRGBModel
    {
        public string Name { get; set; }

        public double R;

        public double G;

        public double B;
    }

}
